{
 "metadata": {
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0-final"
  },
  "orig_nbformat": 2,
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3",
   "language": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2,
 "cells": [
  {
   "source": [
    "# C07. 抽象：类对象"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 7.1 对象\n",
    "\n",
    "-   多态：可对不同类型的对象执行相同的操作\n",
    "-   封装：对外部隐藏有关对象工作原理的细节\n",
    "-   继承：可以基于通用类创建出专用类"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 7.1.1 多态\n",
    "\n",
    "多态(Polymorphism)：源自希腊语，意思是「有多种形态」。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 7.1.2 多态的方法\n",
    "\n",
    "多态形态是 Python 编程方式的核心，也称为鸭子类型。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 7.1.3 封装\n",
    "\n",
    "封装(Encapsulation)：向外部隐藏不必要的细节。\n",
    "\n",
    "-   封装与多态的概念很像，都是抽象的原则。\n",
    "-   多态隐藏了对象所属的类(对象的类型)就能调用其方法；封装隐藏了对象的构造就可以使用其提供的功能。\n"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 7.1.4 继承"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 7.2 类"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 7.2.1 类的概述"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "### 7.2.2 创建自定义类"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Hello, world! I'm Luke Skywalker\nHello, world! I'm Anain Skywalker\n"
     ]
    }
   ],
   "source": [
    "class Person:\n",
    "    def set_name(self,name):\n",
    "        self.name=name\n",
    "        pass\n",
    "    def get_name(self):\n",
    "        return self.name\n",
    "    def greet(self):\n",
    "        print(\"Hello, world! I'm {}\".format(self.name))\n",
    "\n",
    "foo=Person()\n",
    "bar=Person()\n",
    "foo.set_name('Luke Skywalker')\n",
    "bar.set_name('Anain Skywalker')\n",
    "foo.greet()\n",
    "bar.greet()"
   ]
  },
  {
   "source": [
    "### 7.2.3 属性、函数、方法"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Squaawk!\nSquaawk!\n"
     ]
    }
   ],
   "source": [
    "class Bird:\n",
    "    song='Squaawk!'\n",
    "    def sing(self):\n",
    "        print(self.song)\n",
    "\n",
    "bird=Bird()\n",
    "bird.sing()\n",
    "\n",
    "bird_song=bird.sing\n",
    "bird_song()"
   ]
  },
  {
   "source": [
    "### 7.2.4 隐藏\n",
    "\n",
    "Python 没有为私有属性提供直接的支持。\n",
    "\n",
    "在方法或者属性的名称前加上两个下划线即可实现私有(不能从外部访问)。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "The secret message is:\nBet you can't see me...\nBet you can't see me...\n"
     ]
    }
   ],
   "source": [
    "class Secretive:\n",
    "    def __inaccessible(self):\n",
    "        print(\"Bet you can't see me...\")\n",
    "    def accessible(self):\n",
    "        print(\"The secret message is:\")\n",
    "        self.__inaccessible()\n",
    "\n",
    "s=Secretive()\n",
    "# s.__inaccessible()    # 访问会报错\n",
    "s.accessible()\n",
    "# 在类定义中，对所有以两个下划线打头的名称都在形状加上一个下划线和类名\n",
    "s._Secretive__inaccessible()\n",
    "# 如果不希望名称被修改，可以用一个下划线打头进行说明。\n",
    "# from module import * 就不会导入以一个下划线打头的名称"
   ]
  },
  {
   "source": [
    "### 7.2.5 类的命名空间"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "1\n2\n"
     ]
    }
   ],
   "source": [
    "class MemberCounter:\n",
    "    # 在类的作用域内定义一个变量，所有的成员(实例)都可以访问\n",
    "    members=0\n",
    "    def init(self):\n",
    "        MemberCounter.members+=1\n",
    "\n",
    "m1=MemberCounter()\n",
    "m1.init()\n",
    "print(MemberCounter.members)\n",
    "m2=MemberCounter()\n",
    "m2.init()\n",
    "print(MemberCounter.members)"
   ]
  },
  {
   "source": [
    "### 7.2.6 超类"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "f.filter([1,2,3]= [1, 2, 3]\ns.filter()= ['eggs', 'bacon']\n"
     ]
    }
   ],
   "source": [
    "class Filter:\n",
    "    def init(self):\n",
    "        self.blocked=[]\n",
    "    def filter(self,sequence):\n",
    "        return [x for x in sequence if x not in self.blocked]\n",
    "\n",
    "class SPAMFilter(Filter):\n",
    "    def init(self):\n",
    "        self.blocked=['SPAM']\n",
    "\n",
    "f=Filter()\n",
    "f.init()\n",
    "print(\"f.filter([1,2,3]=\",f.filter([1,2,3]))\n",
    "\n",
    "s=SPAMFilter()\n",
    "s.init()\n",
    "print(\"s.filter()=\",s.filter(['SPAM','SPAM','eggs','bacon','SPAM']))"
   ]
  },
  {
   "source": [
    "### 7.2.7 继承"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "True\n(<class '__main__.Filter'>,)\n(<class 'object'>,)\nTrue\n<class '__main__.SPAMFilter'>\n"
     ]
    }
   ],
   "source": [
    "# 判断 SPAMFilter 是不是 Filter 的子类\n",
    "print(issubclass(SPAMFilter,Filter))\n",
    "\n",
    "# 了解 SPAMFilter 的基类\n",
    "print(SPAMFilter.__bases__)\n",
    "print(Filter.__bases__)\n",
    "\n",
    "# 确定对象是否是类的实例\n",
    "print(isinstance(s,SPAMFilter))\n",
    "\n",
    "# 了解对象的类\n",
    "print(s.__class__)"
   ]
  },
  {
   "source": [
    "### 7.2.8 多个超类：多重继承"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Hi, my value is 7\nI am calculator.\n"
     ]
    }
   ],
   "source": [
    "class Calculator:\n",
    "    def calculate(self, expression):\n",
    "        self.value=eval(expression)\n",
    "    def talk(self):\n",
    "        print(\"I am calculator.\")\n",
    "\n",
    "class Talker:\n",
    "    def talk(self):\n",
    "        print(\"Hi, my value is\", self.value)\n",
    "\n",
    "class TalkingCalculator(Talker, Calculator):\n",
    "    # 多个超类具有相同的方法时，将按照方法解析顺序(MRO)访问方法\n",
    "    # 即前面的类的方法覆盖后面的类的方法\n",
    "    pass        \n",
    "\n",
    "class CalculatorTalking(Calculator, Talker):\n",
    "    pass\n",
    "\n",
    "tc=TalkingCalculator()\n",
    "tc.calculate('1+2*3')\n",
    "tc.talk()\n",
    "\n",
    "ct=CalculatorTalking()\n",
    "ct.calculate('1+2*3')\n",
    "ct.talk()"
   ]
  },
  {
   "source": [
    "### 7.2.9 接口 与 内省"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Hi, my value is 7\nTrue\nFalse\nTrue\nFalse\n{'value': 7}\nzYx\n{'value': 7, 'name': 'zYx'}\n"
     ]
    }
   ],
   "source": [
    "tc=TalkingCalculator()\n",
    "tc.calculate('1+2*3')\n",
    "tc.talk()\n",
    "\n",
    "# 确认对象的属性是否存在\n",
    "print(hasattr(tc,'talk'))\n",
    "print(hasattr(tc,'fnord'))\n",
    "\n",
    "# 确认对象的属性是否可以调用\n",
    "print(callable(getattr(tc,'talk',None)))\n",
    "print(callable(getattr(tc,'fnord',None)))\n",
    "\n",
    "# 设置对象的属性(可以增加对象的属性)\n",
    "print(tc.__dict__)\n",
    "setattr(tc,'name','zYx')\n",
    "print(tc.name)\n",
    "\n",
    "# 查看对象的所有的属性\n",
    "print(tc.__dict__)"
   ]
  },
  {
   "source": [
    "### 7.2.10 抽象基类\n",
    "\n",
    "抽象基类是不能实例化的类，其职责是定义子类应该实现的一组抽象方法。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Hi!\n"
     ]
    }
   ],
   "source": [
    "from abc import ABC,abstractmethod\n",
    "\n",
    "class Talker(ABC):\n",
    "    @abstractmethod\n",
    "    def talk(self):\n",
    "        pass\n",
    "\n",
    "# tmp=Talker()    # 实例化会报错\n",
    "\n",
    "class Knigget(Talker):\n",
    "    pass\n",
    "\n",
    "# tmp=Knigget()   # 没有实现抽象方法的子类依然是抽象类，实例化会报错\n",
    "\n",
    "class Knigget(Talker):\n",
    "    def talk(self):\n",
    "        print(\"Hi!\")\n",
    "\n",
    "\n",
    "k=Knigget()\n",
    "k.talk()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "False\nTrue\n"
     ]
    }
   ],
   "source": [
    "# 通过注册子类实现继承关系说明，但是没有真正的继承关系管理\n",
    "class Herring:\n",
    "    def talk(self):\n",
    "        print(\"Blub.\")\n",
    "\n",
    "h=Herring()\n",
    "print(isinstance(h,Talker))\n",
    "\n",
    "Talker.register(Herring)\n",
    "print(isinstance(h,Talker))\n",
    "print(issubclass(Herring,Talker))\n"
   ]
  },
  {
   "source": [
    "## 7.3 面向对象设计的思考\n",
    "\n",
    "-   高内聚\n",
    "-   低耦合\n",
    "-   多引用，少继承\n",
    "-   保持简单\n"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "source": [
    "## 7.4 小结\n",
    "\n",
    "-   对象：由属性和方法组成。\n",
    "    -   属性是对象的变量。\n",
    "-   方法是存储在属性中的函数。\n",
    "-   类：表示一组(或者一类)对象，而每个对象都属于特定的类。\n",
    "    -   类的主要任务是定义其实例将包含的方法。\n",
    "-   多态：能够同样地对待不同类型和类的对象。\n",
    "-   封装：对象可能隐藏(封装)其内部状态。\n",
    "-   继承：超类可以是一个或者多个类的子类；子类也可以拥有一个或者多个超类。\n",
    "-   接口和内省：依赖于多态来调用所需要的方法。\n",
    "-   抽象基类：用于指定子类必须提供的功能，但是自身并不实现这些功能。\n",
    "    -   使用模块 abc 可以创建抽象基类。\n",
    "-   面向对象设计：创造简单并且容易理解的设计。"
   ],
   "cell_type": "markdown",
   "metadata": {}
  }
 ]
}